#include "objviewerwidget.h"
#include <QFile>
#include <QTextStream>
#include <QDir>
#include <QDebug>
#include <QApplication>
#include <QOpenGLShader>

ObjViewerWidget::ObjViewerWidget(QWidget *parent)
    : QOpenGLWidget(parent),
    shaderProgram(nullptr),
    texture(nullptr),
    cameraPosition(0.0f, 0.0f, 5.0f),
    cameraTarget(0.0f, 0.0f, 0.0f),
    cameraUp(0.0f, 1.0f, 0.0f),
    cameraDistance(-55.0f),
    rotation(1.0f, 0.0f, 0.0f, 0.0f),
    modelLoaded(false),
    textureLoaded(false)
{
    setFocusPolicy(Qt::StrongFocus);
}

ObjViewerWidget::~ObjViewerWidget()
{
    makeCurrent();
    delete shaderProgram;
    delete texture;
    vao.destroy();
    vbo.destroy();
    doneCurrent();
}

void ObjViewerWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    setupShader();

    vao.create();
    vao.bind();

    vbo.create();
    vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);

    vao.release();

    this->loadModel(QApplication::applicationDirPath()+"/cottage_obj.obj");
}

void ObjViewerWidget::setupShader()
{
    shaderProgram = new QOpenGLShaderProgram(this);

    // 顶点着色器
    const char *vertexShaderSource =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;\n"
        "layout (location = 1) in vec3 aNormal;\n"
        "layout (location = 2) in vec2 aTexCoord;\n"
        "out vec3 FragPos;\n"
        "out vec3 Normal;\n"
        "out vec2 TexCoord;\n"
        "uniform mat4 model;\n"
        "uniform mat4 view;\n"
        "uniform mat4 projection;\n"
        "void main()\n"
        "{\n"
        "   FragPos = vec3(model * vec4(aPos, 1.0));\n"
        "   Normal = mat3(transpose(inverse(model))) * aNormal;\n"
        "   TexCoord = aTexCoord;\n"
        "   gl_Position = projection * view * vec4(FragPos, 1.0);\n"
        "}\n";

    // 片段着色器
    const char *fragmentShaderSource =
        "#version 330 core\n"
        "in vec3 FragPos;\n"
        "in vec3 Normal;\n"
        "in vec2 TexCoord;\n"
        "out vec4 FragColor;\n"
        "uniform sampler2D texture1;\n"
        "uniform vec3 lightPos;\n"
        "uniform vec3 viewPos;\n"
        "uniform vec3 lightColor;\n"
        "void main()\n"
        "{\n"
        "   // Ambient\n"
        "   float ambientStrength = 0.1;\n"
        "   vec3 ambient = ambientStrength * lightColor;\n"
        "   \n"
        "   // Diffuse\n"
        "   vec3 norm = normalize(Normal);\n"
        "   vec3 lightDir = normalize(lightPos - FragPos);\n"
        "   float diff = max(dot(norm, lightDir), 0.0);\n"
        "   vec3 diffuse = diff * lightColor;\n"
        "   \n"
        "   // Specular\n"
        "   float specularStrength = 0.5;\n"
        "   vec3 viewDir = normalize(viewPos - FragPos);\n"
        "   vec3 reflectDir = reflect(-lightDir, norm);\n"
        "   float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);\n"
        "   vec3 specular = specularStrength * spec * lightColor;\n"
        "   \n"
        "   vec3 result = (ambient + diffuse + specular) * texture(texture1, TexCoord).rgb;\n"
        "   FragColor = vec4(result, 1.0);\n"
        "}\n";

    if (!shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource)) {
        qDebug() << "Vertex shader compilation failed:" << shaderProgram->log();
    }

    if (!shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource)) {
        qDebug() << "Fragment shader compilation failed:" << shaderProgram->log();
    }

    if (!shaderProgram->link()) {
        qDebug() << "Shader program linking failed:" << shaderProgram->log();
    }
}

void ObjViewerWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
    projection.setToIdentity();
    projection.perspective(45.0f, float(w) / float(h), 0.1f, 100.0f);
}

void ObjViewerWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if (!modelLoaded) {
        // 显示一些默认内容或消息
        return;
    }

    shaderProgram->bind();

    // 设置视图矩阵 - 修复相机位置计算
    view.setToIdentity();
    QVector3D cameraPos = cameraTarget + rotation.rotatedVector(QVector3D(0.0f, 0.0f, cameraDistance));
    view.lookAt(cameraPos, cameraTarget, cameraUp);

    // 设置模型矩阵
    model.setToIdentity();

    shaderProgram->setUniformValue("projection", projection);
    shaderProgram->setUniformValue("view", view);
    shaderProgram->setUniformValue("model", model);
    shaderProgram->setUniformValue("lightPos", QVector3D(2.0f, 5.0f, 2.0f));
    shaderProgram->setUniformValue("viewPos", cameraPos);
    shaderProgram->setUniformValue("lightColor", QVector3D(1.0f, 1.0f, 1.0f));

    if (textureLoaded && texture) {
        texture->bind(0);
        shaderProgram->setUniformValue("texture1", 0);
    }

    vao.bind();
    glDrawArrays(GL_TRIANGLES, 0, vertices.size());
    vao.release();

    shaderProgram->release();
}

void ObjViewerWidget::mousePressEvent(QMouseEvent *event)
{
    lastMousePos = event->pos();
}

void ObjViewerWidget::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        int dx = event->x() - lastMousePos.x();
        int dy = event->y() - lastMousePos.y();

        // 计算旋转
        QVector3D right = QVector3D::crossProduct(cameraUp, (cameraTarget - cameraPosition).normalized());
        QQuaternion xRot = QQuaternion::fromAxisAndAngle(cameraUp, dx * 0.5f);
        QQuaternion yRot = QQuaternion::fromAxisAndAngle(right, dy * 0.5f);

        rotation = xRot * yRot * rotation;

        lastMousePos = event->pos();
        update();
    }
}

void ObjViewerWidget::wheelEvent(QWheelEvent *event)
{
    float delta = event->angleDelta().y() * 0.001f;
    cameraDistance *= (1.0f - delta);
    cameraDistance = qMax(1.0f, qMin(cameraDistance, 50.0f));
    update();
}

void ObjViewerWidget::loadModel(const QString &filePath)
{
    makeCurrent();

    if (loadOBJ(filePath)) {
        modelLoaded = true;

        // 尝试加载对应的纹理
        QFileInfo fileInfo(filePath);
        QString baseName = fileInfo.completeBaseName();
        QString dirPath = fileInfo.absolutePath();

        // 查找可能的纹理文件
        QStringList textureExtensions = {"png", "jpg", "jpeg", "bmp", "tga"};
        for (const QString &ext : textureExtensions) {
            QString texturePath = dirPath + "/" + baseName + "." + ext;
            if (QFile::exists(texturePath)) {
                if (loadTexture(texturePath)) {
                    break;
                }
            }
        }

        update();
    }
}

bool ObjViewerWidget::loadOBJ(const QString &filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "Failed to open OBJ file:" << filePath;
        return false;
    }

    QVector<QVector3D> tempVertices;
    QVector<QVector3D> tempNormals;
    QVector<QVector2D> tempTexCoords;
    QVector<Vertex> tempVerticesOut;

    QTextStream in(&file);
    while (!in.atEnd()) {
        QString line = in.readLine().trimmed();
        if (line.isEmpty() || line.startsWith("#")) {
            continue;
        }

        QStringList parts = line.split(" ", Qt::SkipEmptyParts);
        if (parts.isEmpty()) continue;

        if (parts[0] == "v") {
            // 顶点位置
            if (parts.size() >= 4) {
                QVector3D vertex(
                    parts[1].toFloat(),
                    parts[2].toFloat(),
                    parts[3].toFloat()
                    );
                tempVertices.append(vertex);
            }
        } else if (parts[0] == "vn") {
            // 法线
            if (parts.size() >= 4) {
                QVector3D normal(
                    parts[1].toFloat(),
                    parts[2].toFloat(),
                    parts[3].toFloat()
                    );
                tempNormals.append(normal);
            }
        } else if (parts[0] == "vt") {
            // 纹理坐标
            if (parts.size() >= 3) {
                QVector2D texCoord(
                    parts[1].toFloat(),
                    1.0f - parts[2].toFloat()  // OBJ纹理坐标需要翻转Y轴
                    );
                tempTexCoords.append(texCoord);
            }
        } else if (parts[0] == "f") {
            // 面 - 需要正确处理三角面和四边形面
            if (parts.size() < 4) continue;

            // 将面转换为三角形
            QVector<QStringList> faceVertices;
            for (int i = 1; i < parts.size(); i++) {
                faceVertices.append(parts[i].split("/"));
            }

            // 三角化 (扇形三角化)
            for (int i = 1; i < faceVertices.size() - 1; i++) {
                // 三个顶点构成一个三角形
                for (int j = 0; j < 3; j++) {
                    int vertexIndex = 0;
                    if (j == 0) vertexIndex = 0;
                    else if (j == 1) vertexIndex = i;
                    else vertexIndex = i + 1;

                    Vertex vertex;

                    // 顶点位置
                    if (faceVertices[vertexIndex].size() > 0 && !faceVertices[vertexIndex][0].isEmpty()) {
                        int idx = faceVertices[vertexIndex][0].toInt() - 1;
                        if (idx >= 0 && idx < tempVertices.size()) {
                            vertex.position = tempVertices[idx];
                        }
                    }

                    // 纹理坐标
                    if (faceVertices[vertexIndex].size() > 1 && !faceVertices[vertexIndex][1].isEmpty()) {
                        int idx = faceVertices[vertexIndex][1].toInt() - 1;
                        if (idx >= 0 && idx < tempTexCoords.size()) {
                            vertex.texCoord = tempTexCoords[idx];
                        } else {
                            vertex.texCoord = QVector2D(0.0f, 0.0f);
                        }
                    } else {
                        vertex.texCoord = QVector2D(0.0f, 0.0f);
                    }

                    // 法线
                    if (faceVertices[vertexIndex].size() > 2 && !faceVertices[vertexIndex][2].isEmpty()) {
                        int idx = faceVertices[vertexIndex][2].toInt() - 1;
                        if (idx >= 0 && idx < tempNormals.size()) {
                            vertex.normal = tempNormals[idx];
                        } else {
                            // 如果没有法线，计算默认法线
                            vertex.normal = QVector3D(0.0f, 1.0f, 0.0f);
                        }
                    } else {
                        vertex.normal = QVector3D(0.0f, 1.0f, 0.0f);
                    }

                    tempVerticesOut.append(vertex);
                }
            }
        }
    }

    file.close();

    if (tempVerticesOut.isEmpty()) {
        qDebug() << "No vertices loaded from OBJ file";
        return false;
    }

    // 如果模型没有法线，计算面法线
    if (tempNormals.isEmpty()) {
        calculateNormals(tempVerticesOut);
    }

    vertices = tempVerticesOut;

    // 更新顶点缓冲区
    updateVertexBuffer();

    qDebug() << "Loaded OBJ model with" << vertices.size() << "vertices";
    return true;
}

void ObjViewerWidget::updateVertexBuffer()
{
    makeCurrent();

    vao.bind();
    vbo.bind();
    vbo.allocate(vertices.constData(), vertices.size() * sizeof(Vertex));

    shaderProgram->bind();

    // 设置顶点属性指针
    shaderProgram->enableAttributeArray(0);
    shaderProgram->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, position), 3, sizeof(Vertex));

    shaderProgram->enableAttributeArray(1);
    shaderProgram->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, normal), 3, sizeof(Vertex));

    shaderProgram->enableAttributeArray(2);
    shaderProgram->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, texCoord), 2, sizeof(Vertex));

    shaderProgram->release();
    vbo.release();
    vao.release();
}

void ObjViewerWidget::calculateNormals(QVector<Vertex> &vertices)
{
    // 为每个顶点初始化法线
    for (int i = 0; i < vertices.size(); i++) {
        vertices[i].normal = QVector3D(0.0f, 0.0f, 0.0f);
    }

    // 计算每个面的法线并累加到顶点
    for (int i = 0; i < vertices.size(); i += 3) {
        if (i + 2 < vertices.size()) {
            QVector3D v1 = vertices[i].position;
            QVector3D v2 = vertices[i+1].position;
            QVector3D v3 = vertices[i+2].position;

            QVector3D edge1 = v2 - v1;
            QVector3D edge2 = v3 - v1;
            QVector3D faceNormal = QVector3D::crossProduct(edge1, edge2).normalized();

            vertices[i].normal += faceNormal;
            vertices[i+1].normal += faceNormal;
            vertices[i+2].normal += faceNormal;
        }
    }

    // 标准化所有法线
    for (int i = 0; i < vertices.size(); i++) {
        vertices[i].normal.normalize();
    }
}

bool ObjViewerWidget::loadTexture(const QString &filePath)
{
    makeCurrent();

    if (texture) {
        delete texture;
        texture = nullptr;
    }

    texture = new QOpenGLTexture(QImage(filePath).mirrored());
    if (!texture->isCreated()) {
        qDebug() << "Failed to load texture:" << filePath;
        delete texture;
        texture = nullptr;
        textureLoaded = false;
        return false;
    }

    texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
    texture->setMagnificationFilter(QOpenGLTexture::Linear);
    texture->setWrapMode(QOpenGLTexture::Repeat);

    textureLoaded = true;
    qDebug() << "Loaded texture:" << filePath;
    return true;
}
